using CfgTable;
using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using IQIGame.Onigao.GameAOT;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

namespace IQIGame.Onigao.GamePlay
{
    public class UILevelMap : UIBaseWindow, IMapContainer
    {
        public static async UniTask<bool> TryGoto(int questCid)
        {
            var questConfig = TableCenter.quest.Get(questCid);
            if (questConfig == null || questConfig.TargetRegion == 0)
            {
                return false;
            }

            await Open(questConfig.TargetRegion, questConfig.TargetShowEntity.FirstOrDefault());
            return true;
        }

        public static async UniTask Open(int regionCid, int targetMcid)
        {
            if (!FunctionModule.CheckIsOpenAndTip(FunctionType.Map))
                return;
            var map = await UIMapManager.Instance.LoadMap(regionCid);
            ManagerCenter.UI.ShowWindowAsync<UILevelMap>(UD_LevelMap.Create(map, targetMcid)).Forget();
        }

        #region Template Generate,don't modify

        protected class UIB_UILevelMap
        {
            public ExButton btnClose { protected set; get; }
            public GameObject memontoPanel { protected set; get; }
            public GameObject floorPanel { protected set; get; }
            public GameObject scaleSlider { protected set; get; }
            public ExButton btnWorldMap { protected set; get; }
            public ExButton btnTerrain { protected set; get; }
            public GameObject questPanel { protected set; get; }
            public GameObject teleportPanel { protected set; get; }
            public GameObject regionPanel { protected set; get; }
            public GameObject mapContainer { protected set; get; }
            public ScrollRect scrollRect { protected set; get; }
            public ExRawImage backGround { protected set; get; }
            public RectTransform tempContainerRT { protected set; get; }
            public GameObject tracePanel { protected set; get; }
            public GameObject questListPanel { protected set; get; }
            public ExButton panelMask { protected set; get; }
            public ExButton btnHome { protected set; get; }

            public virtual void InitBinding(ObjectBinding __binding)
            {
                __binding.TryGetVariableValue<ExButton>("btnClose", out var __tbv0);
                btnClose = __tbv0;
                __binding.TryGetVariableValue<GameObject>("memontoPanel", out var __tbv1);
                memontoPanel = __tbv1;
                __binding.TryGetVariableValue<GameObject>("floorPanel", out var __tbv2);
                floorPanel = __tbv2;
                __binding.TryGetVariableValue<GameObject>("scaleSlider", out var __tbv3);
                scaleSlider = __tbv3;
                __binding.TryGetVariableValue<ExButton>("btnWorldMap", out var __tbv4);
                btnWorldMap = __tbv4;
                __binding.TryGetVariableValue<ExButton>("btnTerrain", out var __tbv5);
                btnTerrain = __tbv5;
                __binding.TryGetVariableValue<GameObject>("questPanel", out var __tbv6);
                questPanel = __tbv6;
                __binding.TryGetVariableValue<GameObject>("teleportPanel", out var __tbv7);
                teleportPanel = __tbv7;
                __binding.TryGetVariableValue<GameObject>("regionPanel", out var __tbv8);
                regionPanel = __tbv8;
                __binding.TryGetVariableValue<GameObject>("mapContainer", out var __tbv9);
                mapContainer = __tbv9;
                __binding.TryGetVariableValue<ScrollRect>("scrollRect", out var __tbv10);
                scrollRect = __tbv10;
                __binding.TryGetVariableValue<ExRawImage>("backGround", out var __tbv11);
                backGround = __tbv11;
                __binding.TryGetVariableValue<RectTransform>("tempContainerRT", out var __tbv12);
                tempContainerRT = __tbv12;
                __binding.TryGetVariableValue<GameObject>("tracePanel", out var __tbv13);
                tracePanel = __tbv13;
                __binding.TryGetVariableValue<GameObject>("questListPanel", out var __tbv14);
                questListPanel = __tbv14;
                __binding.TryGetVariableValue<ExButton>("panelMask", out var __tbv15);
                panelMask = __tbv15;
                __binding.TryGetVariableValue<ExButton>("btnHome", out var __tbv16);
                btnHome = __tbv16;
            }
        }

        #endregion Template Generate,don't modify


        #region Window Config

        /// <summary>
        /// 静态配置
        /// </summary>
        private static UICreateConfig _createConfig = new()
        {
            prefabName = nameof(UILevelMap),
            layer = EUILayer.Normal,
            parentPath = "Map",
        };

        /// <summary>
        /// 创建UI的配置
        /// </summary>
        public override IUICreateConfig createConfig => _createConfig;

        #endregion Window Config

        #region fields

        private UIN_LevelMapMemontoPanel _memontoPanel;
        private UIN_LevelMapFloorPanel _floorPanel;
        private UIN_LevelMapScaleSlider _scaleSlider;

        private UIN_LevelMapRegionPanel _regionPanel;
        private UIN_LevelMapTeleportPanel _teleportPanel;
        private UIN_LevelMapQuestPanel _questPanel;
        private UIN_LevelMapTracePanel _tracePanel;
        private UIN_LevelMapQuestListPanel _questListPanel;

        private UIMapRoot _mapRoot;

        private UIN_LevelMapTempContainer _tempContainer;

        #endregion fields

        #region properties

        protected UIB_UILevelMap ui { get; set; }
        protected UIMsgDispatcher uiMsgDispatcher => _msgDispatcher as UIMsgDispatcher;

        #endregion properties

        protected override void BeforeInit()
        {
            ui = new UIB_UILevelMap();
            ui.InitBinding(csObjBind);
        }

        protected override void OnInit()
        {
            ui.btnClose.AddClickEvent(Close);
            ui.panelMask.AddClickEvent(OnPanelMaskClick);
            ui.btnWorldMap.AddClickEvent(OnBtnWorldMapClick);
            ui.btnTerrain.AddClickEvent(OnBtnTerrainClick);
            ui.btnHome.AddClickEvent(() => _mapRoot.GetLayer((int)StaticLayerType.FogLayer).RemoveSymbol());
            ui.btnTerrain.SetActive(false);

            _memontoPanel = InitChildNode<UIN_LevelMapMemontoPanel>(ui.memontoPanel);
            _floorPanel = InitChildNode<UIN_LevelMapFloorPanel>(ui.floorPanel);
            _scaleSlider = InitChildNode<UIN_LevelMapScaleSlider>(ui.scaleSlider);

            _allPanels = new List<UIBaseNode>();
            _panelStack = new Stack<UIBaseNode>();
            _regionPanel = InitChildNode<UIN_LevelMapRegionPanel>(ui.regionPanel);
            _allPanels.Add(_regionPanel);
            var regions = ListPool<int>.Get();
            var regionCfgList = TableCenter.regionInstance.DataList;
            for (var i = 0; i < regionCfgList.Count; i++)
            {
                regions.Add(TableCenter.regionInstance.DataList[i].Id);
            }

            _regionPanel.Refresh(regions);
            ListPool<int>.Put(regions);
            _teleportPanel = InitChildNode<UIN_LevelMapTeleportPanel>(ui.teleportPanel);
            _allPanels.Add(_teleportPanel);
            _questPanel = InitChildNode<UIN_LevelMapQuestPanel>(ui.questPanel);
            _allPanels.Add(_questPanel);
            _tracePanel = InitChildNode<UIN_LevelMapTracePanel>(ui.tracePanel);
            _allPanels.Add(_tracePanel);
            _questListPanel = InitChildNode<UIN_LevelMapQuestListPanel>(ui.questListPanel);
            _allPanels.Add(_questListPanel);

            _tempContainer = new UIN_LevelMapTempContainer(ui.tempContainerRT);
            _posCache = new Dictionary<int, Vector3>();
            _scaleCache = new Dictionary<int, float>();
        }

        protected override void OnShow(UIBaseData data)
        {
            var d = data as UD_LevelMap;
            BindMap(d.mapRoot, d.targetMcid);
            PushPanel(_regionPanel);
        }

        protected override void OnHide()
        {

        }

        private void OnPanelMaskClick()
        {
            PopPanel();
            if (_panelStack.Count == 0)
            {
                PushPanel(_regionPanel);
            }
        }

        private void BindMap(UIMapRoot map, int targetMcid)
        {
            if (map == null)
            {
                Debug.LogError("Map is null");
                return;
            }

            var curMap = UIMapManager.Instance.GetMap(GameplayAreaManager.Instance.curSceneArea.curRegionCid);
            curMap.AttachTo(_tempContainer);
            map.AttachTo(this);
            _scaleSlider.Show();
            _mapRoot.FocusPlayer(false);
            _targetMcid = targetMcid;
        }

        private void OnTeleportClick(IMapSymbolData data)
        {
            PushPanel(_teleportPanel);
            _teleportPanel.Refresh(data, _regionPanel.CurRegion);
        }

        private void OnQuestTargetClick()
        {
            PushPanel(_questPanel);
            _questPanel.Refresh(GameDataCenter.PlayerData.quest.trackQuestCid, 0);
        }

        private void OnQuestClick(IMapSymbolData data)
        {
            var entity = GameplayAreaManager.Instance.curSceneArea.GetEntityByMcid(data.mcid);
            var quests = ListPool<int>.Get();
            entity.FilterAcceptableQuests(quests);
            if (quests.Count == 1)
            {
                PushPanel(_questPanel);
                _questPanel.Refresh(quests.First(), entity.id);
            }
            else
            {
                PushPanel(_questListPanel);
                _questListPanel.Refresh(data.entityId, quests);
            }

            ListPool<int>.Put(quests);
        }

        private void MapClickFallBack(IMapSymbolData data)
        {
            if (data == null || data.config.Type == MapUiEntityType.Player)
            {
                return;
            }

            if (data.isCheckPointActive)
            {
                OnTeleportClick(data);
            }
            else
            {
                PushPanel(_tracePanel);
                _tracePanel.Refresh(data);
            }
        }

        public async UniTaskVoid DoTraceEntity(int targetEntityId)
        {
            if (!FunctionModule.CheckIsOpenAndTip(FunctionType.MapTransmit))
                return;

            if (targetEntityId == 0)
            {
                return;
            }

            var curArea = GameplayAreaManager.Instance.curSceneArea;
            var targetPos = curArea.GetEntityById(targetEntityId)?.transform?.position ??
                            Vector3.positiveInfinity;
            var playerPos = curArea.GetPlayerAvatarEntity().transform.position;
            //距离过近的直接弹tip
            if (Vector3.Distance(targetPos, playerPos) <= LevelDataConsts.QuadTreeSearchHalfSize)
            {
                NoticeModule.ShowNoticeNoCall(500014);
                return;
            }

            if (_mapRoot.regionCid == curArea.curRegionCid)
            {
                await curArea.MarkTrackingEntity(targetEntityId);
                _mapRoot.ChangeTraceEntity();
                NoticeModule.ShowNotice(APIUIConst.NoticeCid_SameRegionTrace,
                    () => TeleportToCurRegion(targetPos));
            }
            else
            {
                NoticeModule.ShowNotice(APIUIConst.NoticeCid_DifferentRegionTrace,
                    () => TeleportToOtherRegion(targetEntityId, targetPos).Forget());
            }
        }

        public async UniTaskVoid CancelTraceEntity()
        {
            if (GameplayAreaManager.Instance.curArea is not IGameplaySceneArea curArea)
            {
                return;
            }

            await curArea.MarkTrackingEntity(0);
            _mapRoot.ChangeTraceEntity();
        }

        private void TeleportToCurRegion(Vector3 targetPos)
        {
            var checkPoint = _mapRoot.GetNearestCheckPointMcid(targetPos);
            if (checkPoint != null)
            {
                CLevelLogicModule.NetCore.CS_TeleportToEntity(checkPoint.entityId);
            }

            Close();
        }

        private async UniTaskVoid TeleportToOtherRegion(int targetEntityId, Vector3 targetPos)
        {
            if (GameplayAreaManager.Instance.curArea is not IGameplaySceneArea curArea)
            {
                return;
            }

            var checkPoint = _mapRoot.GetNearestCheckPointMcid(targetPos);
            if (checkPoint != null)
            {
                await curArea.TeleportToRegion(_mapRoot.regionCid, checkPoint.entityId);
                await curArea.MarkTrackingEntity(targetEntityId);
                _mapRoot.ChangeTraceEntity();
            }
        }

        protected override void OnDispose()
        {
            _allPanels.Clear();
            _allPanels = null;
            _mapRoot.DetachFrom(this);
            _tempContainer.Clear();
            UIMapManager.Instance.SetSelection(null);
        }

        #region methonds

        private void OnBtnTerrainClick()
        {
            //todo by xg: show terrain
        }

        private void OnBtnWorldMapClick()
        {
            //todo by xg: show worldMap
        }

        private void OnScaleChanged(float value)
        {
            _mapRoot.SetScale(value);
        }

        private async UniTask RefreshMap()
        {
            _mapUIData = await MapUIModule.Instance.GetMapData(_mapRoot.areaType, _mapRoot.regionCid);
            if (_mapUIData == null)
            {
                return;
            }

            foreach (var entity in _mapUIData.entities)
            {
                if (entity.mapUIEntityCid == 0 ||
                    TableCenter.mapUiEntity.Get(entity.mapUIEntityCid).Type == MapUiEntityType.Fog)
                    continue;
                _mapRoot.AddSymbol(entity);
            }

            _mapRoot.RefreshAllTracer();
            _mapRoot.FocusTarget(_targetMcid, out var target);
            if (target != null)
            {
                UIMapManager.Instance.SetSelection(target);
                HandleSymbolInteract(target.data);
            }
            else
            {
                HandleSymbolInteract(null);
            }
        }

        public async UniTaskVoid SwitchRegion(int regionCid)
        {
            if (regionCid == _mapRoot.regionCid)
            {
                return;
            }

            _switchTarget = regionCid;
            var target = UIMapManager.Instance.GetMap(regionCid);
            if (target == null)
            {
                target = await UIMapManager.Instance.LoadMap(regionCid);
                //由SwitchRegion加载的地图全部挂到tempContainer下，在界面关闭时统一卸载
                target.AttachTo(_tempContainer);
            }

            //确保即使有多个异步加载在运行，也能正确显示目标地图
            if (_switchTarget == regionCid)
            {
                _posCache[_mapRoot.regionCid] = _mapRoot.transform.localPosition;
                _scaleCache[_mapRoot.regionCid] = _mapRoot.transform.localScale.x;
                _mapRoot.DetachFrom(this);
                target.AttachTo(this);
            }
        }

        public void PopPanel()
        {
            if (_panelStack.TryPop(out var panel))
            {
                panel.Hide();
            }

            if (_panelStack.TryPeek(out var prevPanel))
            {
                prevPanel.Show();
            }

            ui.panelMask.SetActive(_panelStack.Count > 1);
        }

        public void PushPanel(UIBaseNode panel)
        {
            if (_panelStack.TryPeek(out var prevPanel))
            {
                prevPanel.Hide();
            }

            _panelStack.Push(panel);
            panel.Show();
            ui.panelMask.SetActive(_panelStack.Count > 1);
        }

        public T GetPanel<T>() where T : UIBaseNode
        {
            foreach (var panel in _allPanels)
            {
                if (panel is T result)
                {
                    return result;
                }
            }

            return null;
        }

        #endregion methonds

        #region IMapContainer implement

        public RectTransform containerRT => ui.mapContainer.transform as RectTransform;

        public void OnMapAttach(UIMapRoot root)
        {
            _mapRoot = root;
            ui.scrollRect.content = root.transform;
            if (_posCache.TryGetValue(root.regionCid, out var lastPos))
            {
                _mapRoot.transform.localPosition = lastPos;
            }

            if (_scaleCache.TryGetValue(root.regionCid, out var lastScale))
            {
                _mapRoot.transform.localScale = Vector3.one * lastScale;
                _scaleSlider.SetValue(lastScale * 100);
            }

            _scaleSlider.OnSliderValueChange += OnScaleChanged;
            RefreshMap().Forget();
        }

        public void OnMapDetach()
        {
            _scaleSlider.OnSliderValueChange -= OnScaleChanged;
            _mapUIData?.Put2Pool();
            _mapRoot.ClearSymbols();
            _mapUIData = null;
            _mapRoot = null;
        }

        public bool FilterMapSymbol(IMapSymbolData data)
        {
            return data.config.MapDisplay is MapDisplayType.All or MapDisplayType.OnlyMap;
        }

        public void HandleSymbolInteract(IMapSymbolData data)
        {
            if (data == null)
            {
                return;
            }

            switch (data.config.Type)
            {
                case MapUiEntityType.Quest:
                    OnQuestClick(data);
                    break;
                case MapUiEntityType.QuestTarget:
                case MapUiEntityType.QuestArea:
                    OnQuestTargetClick();
                    break;
                default:
                    MapClickFallBack(data);
                    break;
            }
        }

        public float radius => float.MaxValue;

        #endregion

        private MapUIData _mapUIData;

        private int _targetMcid;

        private int _switchTarget;

        private List<UIBaseNode> _allPanels;
        private Stack<UIBaseNode> _panelStack;

        private Dictionary<int, Vector3> _posCache;
        private Dictionary<int, float> _scaleCache;
    }
}